﻿using DotNetOpenAuth.OAuth2;
using Google.Apis.Authentication;
using Google.Apis.Authentication.OAuth2;
using Google.Apis.Authentication.OAuth2.DotNetOpenAuth;
using Google.Apis.Drive.v2;
using Google.Apis.Util;
using System;
using System.Diagnostics;

namespace PB138___projekt
{
    /// <summary>
    /// Represents authenticator that allows user authentication.
    /// </summary>
    class UserAuth : IAuth
    {
        private const string CLIENT_ID
            = "515108601197-5sm7np20o2bkjvsiqk4dk8in4fvj701p.apps.googleusercontent.com";
        private const string CLIENT_SECRET = "EOO4RKjB58emGC9R9SzqhvJC";

        IAuthenticator authenticator;
        NativeApplicationClient provider;
        IAuthorizationState state;
        Uri authUri;
        string authCode;

        /// <summary>
        /// Gets authenticator.
        /// </summary>
        public IAuthenticator Authenticator
        {
            get { return authenticator; }
        }

        /// <summary>
        /// Gets type of authenticator.
        /// </summary>
        public AuthenticatorType AuthenticatorType
        {
            get { return AuthenticatorType.UserAuthenticator; }
        }

        /// <summary>
        /// Constructor for creating instances of <c>UserAuth</c>.
        /// </summary>
        /// <remarks>
        /// To completly create valid authenticator it's necessary to call
        /// <c>AskForAuthorization</c> and <c>CreateAuthenticator</c> methods.
        /// </remarks>
        public UserAuth()
        {
            authenticator = null;

            // Register the authenticator
            provider = new NativeApplicationClient
                            (
                                GoogleAuthenticationServer.Description,
                                CLIENT_ID,
                                CLIENT_SECRET
                            );

            // Get the auth URL
            state = new AuthorizationState(new[] 
                            {
                                DriveService.Scopes.Drive.GetStringValue()
                            });
            state.Callback = new Uri(NativeApplicationClient.OutOfBandCallbackUrl);
            authUri = provider.RequestUserAuthorization(state);
        }

        /// <summary>
        /// Opens website where the user is asked to log in to Google account and
        /// to allow the application to access to a file stored on Google Drive.
        /// User gets an authorization code there.
        /// </summary>
        /// <remarks>To complete authenticator creation use <c>CreateAuthenticator</c>
        /// giving it authentication code as an argument.</remarks>
        public void AskForAuthorization()
        {
            Process.Start(authUri.ToString());
        }

        /// <summary>
        /// Finishes the process of creating of authenticator.
        /// </summary>
        /// <param name="authCode">Athentication code got from website using
        /// <c>AskForAuthorization</c> method.</param>
        /// <exception cref="ArgumentNullException">
        /// If <paramref name="authCode"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="ArgumentException">If <paramref name="authCode"/> is
        /// empty or consists only of white-space characters.</exception>
        /// <remarks>
        /// To get authentication code use <c>AskForAuthorization</c> method.
        /// </remarks>
        public void CreateAuthenticator(string authCode)
        {
            if (authCode == null)
            {
                throw new ArgumentNullException("authCode");
            }

            if (string.IsNullOrEmpty(authCode) || string.IsNullOrWhiteSpace(authCode))
            {
                throw new ArgumentException("Authentication code is empty or consists"
                    + " only of white-space characters!", "authCode");
            }

            this.authCode = authCode;
            authenticator = new OAuth2Authenticator<NativeApplicationClient>
                                    (
                                        provider,
                                        GetAuthorization
                                    );
        }


        private IAuthorizationState GetAuthorization(NativeApplicationClient arg)
        {
            // Retrieve the access token by using the authorization code.
            return arg.ProcessUserAuthorization(authCode, state);
        }
    }
}
